﻿module BreakRuns
 //Takes a char of value 0 or 1 and returns the opposite value
    let complement x =
        match x with
        | '1' -> '0'
        | '0' -> '1'
        | _ -> ' '
  //Takes two arrays and in index and inserts the second array into the first one at the given index
    let insert (arr : char array) x i =
        let str =  System.String.Concat(arr)
        let temp = str.Substring(0,i)
        let y = Array.append (temp.ToCharArray()) x 
        let temp = str.Substring(i)
        Array.append y (temp.ToCharArray()) 
   //Makes sure the given array has no more than d of same element in a row. The final array will have a length of L+ 2*L/(2 d - 1) + 2
    let BreakRuns (X : char array) d =
        let u = (d - 1) 
        let s = X.Length/(2*u) 
        let t = s * u 
        let mid = X.Length/2 
        let b = [|for i in 1 .. s ->(complement (X.[(X.Length-(u*(i+1))+1)]))|] 
        let a = [|for i in 0 .. s-1 ->(complement (X.[(u*(i+1))]))|]
        let d = [|complement (X.[mid]); complement (X.[(mid + 1)])|] 
        let L = [|'a'|]
        let mutable final = X
        let mutable count = 0;
        for i in 0 .. X.Length-1 do 
            if((i)%u=0 && i < t-1) then 
                final <- insert final [|a.[i/u]|] (i+count+1)
                count <- count + 1
            if (i+1=mid) then
                final <- insert final d (i+count)
                count <- count + 1 
            if((X.Length-i+1)%u=0 && i > (X.Length - t)) then
                final <- insert final [|a.[(X.Length-i+1)/u-1]|] (i+count-1)
                count <- count + 1 
        final
//Takes an array, if its length is odd then it adds a zero to the end, then it adds k ones to both ends where k is max(k2, k3), and then applies BreakRuns to it. Finally, it switches all 0's to A'S or C's and 1's to T's and G's with frequency equal to gamma.
    let BreakRunsWrapper (X : char array) d k2 k3 (gamma : double) = 
        let mutable y = [||]
        if (X.Length%2 = 0) then
             y <- X
        else
            y <- Array.append X [|'0'|]
            
        let mutable k = 0
        if(k2>k3) then
            k <- k2
        else
            k <- k3
        let temp = k
        let z = [| for i in 0 .. temp-1 -> '1'|]
        let y1 = Array.append (Array.append z y) z
        let y2 = BreakRuns y1 d
        let pos = int (Operators.floor (1.0 / gamma))
        let y3 = [| for i in 0 .. y2.Length-1 ->
                    if (y2.[i]='0') then
                        if(i%pos=0) then
                            'C'
                        else
                            'A'
                    else
                        if(i%pos=0) then
                            'G'
                        else
                            'T'|]
        y3
//Applies BreakRunsWrapper to every column in a matrix
    let BreakRunsWrapperMatrix (X : char[,]) d k2 k3 (gamma : double) = 
        let matrix = [|for i in 0 .. (X.GetLength 0)-1 -> BreakRunsWrapper [|for j in 0 .. ((X.Length/X.GetLength 0) - 1)->X.[i,j]|] d k2 k3 gamma|]
        let temp1 = matrix.[0]
        //X.
        let final = Array2D.zeroCreate (X.GetLength 0)  ((X.Length/X.GetLength 0) )
        for i in 0 .. X.GetLength 0 - 1 do
            for j in 0 .. ((X.Length/X.GetLength 0) - 1) do
                let temp = matrix.[i]
                final.[i,j] <- temp.[j]
        final

    let RunBRArray n l d k1 k2 k3 k4 (gamma : double) = 
        let X = DWFx.DetWords n l k1 k4 DWFx.BIN_GLUE_SET
        let BROut = BreakRunsWrapperMatrix X d k2 k3 gamma
        let bob = BROut.GetLength(1)
        BROut

    let RunBR n l d k1 k2 k3 k4 (gamma : double) = 
        let X = DWFx.DetWords n l k1 k4 DWFx.BIN_GLUE_SET
        let BROut = BreakRunsWrapperMatrix X d k2 k3 gamma
        let bob = BROut.GetLength(1)
        let Mbox = Array.init bob (fun i -> utils.getColumn i BROut)
        tester.testBasicHammingConstraint Mbox k1
        //tester.testReverseComplementaryConstraint Mbox k2
        //tester.testSelfReverseComplementaryConstraint Mbox k3
        //tester.testShiftingHammingConstraint Mbox k4
        //tester.testGCContentConstraint Mbox gamma
        Mbox
        (*
        let createTable =
            let p = BROut.GetLength(0)
            let q = BROut.GetLength(1)
            let mutable tableString = ""
            for i = 0 to (p-1) do
                tableString <- tableString + "<tr><td>Word " + string (i+1) + ": &nbsp; 3'</td>"
                for j = 0 to (q-1) do
                    if BROut.[i,j] = 'A' then
                        tableString <- tableString + "<td style=\"background-color: #5050ff; padding: .3em; color: black;\">" + "A" + "</td>"
                    elif BROut.[i,j] = 'C' then
                        tableString <- tableString + "<td style=\"background-color: #e00000; padding: .3em; color: black;\">" + "C" + "</td>"
                    elif BROut.[i,j] = 'T' then
                        tableString <- tableString + "<td style=\"background-color: #e6e600; padding: .3em; color: black;\">" + "T" + "</td>"
                    elif BROut.[i,j] = 'G' then
                        tableString <- tableString + "<td style=\"background-color: #00c000; padding: .3em; color: black;\">" + "G" + "</td>"
                    //tableString <- tableString + "<td>" + final_M.[i,j].ToString() + "</td>"
                done
                tableString <- tableString + "<td>5'</td></tr><tr><td>&nbsp;</td></tr>"
            done
            tableString
            
        sprintf "%s" createTable
        *)
